package com.quick.mybatis.service.impl;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

import com.quick.mybatis.mapper.CommonCacheMapper;
import com.quick.mybatis.mapper.CommonMapper;
import com.quick.mybatis.model.PageModel;
import com.quick.mybatis.service.MybatisService;
import com.quick.mybatis.utils.ObjectUtil;

public abstract class MybatisServiceImpl<T> implements MybatisService<T> {
	
	protected final static Log logger = LogFactory.getLog(MybatisServiceImpl.class);


	private CommonCacheMapper<T> commonCacheMapper;

	
	public abstract CommonMapper<T> getCommonMapper() ;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer save(T t) {

		try {
			Integer result = this.getCommonMapper().insert(t);
			/*
			 * if(result== null || result <= 0){ throw new RuntimeException(
			 * "Operating data of failure."); }
			 */
			return result;
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer update(T t) {
		try {
			Integer result = getCommonMapper().update(t);
			if (result == null || result <= 0) {
				throw new RuntimeException("Operating data of failure.");
			}
			return result;
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<T> getList(T t) {
		try {
			return (List<T>) ObjectUtil.mapConvetObject(getCommonMapper().getList(t), t.getClass());
		} catch (Exception e) {
			logger.error(e);
			return new ArrayList<T>();
		}
	}

	@Override
	public T getById(final String id) {
		Class<T> c=getEntryClass();
		try {
			Executer excuter=new Executer(){
				@Override
				public Object exec() {
					return getCommonMapper().getById(id);
				}
			};
			return (T) ObjectUtil.mapConvetObject((List)execLocal(excuter),getEntryClass());
		} catch (Exception e) {
			try {
				return (T) ObjectUtil.createNewInstance(c);
			} catch (InstantiationException e1) {
				logger.error(e1);
				return null;
			} catch (IllegalAccessException e1) {
				logger.error(e1);
				return null;
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer delete(T t) {
		try {
			Integer result = getCommonMapper().delete(t);
			if (result == null || result <= 0) {
				throw new RuntimeException("Operating data of failure.");
			}
			return result;
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	public void getPageList(PageModel<T> page, Object t) throws Exception {
		try {
			page.setTotalCount(getCommonMapper().getPageListCount(page));
			page.setItems((List<T>) ObjectUtil.mapConvetObject(getCommonMapper().getPageList(page),
					page.getItem().getClass()));
		} catch (Exception e) {
			logger.error(e);
			throw e;
		}
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer saveAll(List<T> list) {
		try {
			Integer result = getCommonMapper().insertAll(list);
			/*
			 * if(result== null || result <= 0){ throw new RuntimeException(
			 * "Operating data of failure."); }
			 */
			return result;
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	public Integer getCountList(T page) {
		return getCommonMapper().getListCount(page);
	}

	@Override
	public void getPageList(PageModel<T> page, Object obj, boolean isCache) throws Exception {
		if (isCache) {
			try{
			page.setTotalCount(this.commonCacheMapper.getPageListCount(page));
			page.setItems((List<T>) ObjectUtil.mapConvetObject(getCommonMapper().getPageList(page),
					page.getItem().getClass()));
			}catch(Exception e){
				logger.error(e);
			}
		} else {
			this.getPageList(page, obj);
		}

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer save(T t, boolean isCache) {
		try {
			if (isCache) {
				Integer result = this.commonCacheMapper.insert(t);
				if (result == null || result <= 0) {
					throw new RuntimeException("Operating data of failure.");
				}
				return result;
			} else {
				return this.save(t);
			}
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer update(T t, boolean isCache) {
		try {
			if (isCache) {
				Integer result = this.commonCacheMapper.update(t);
				if (result == null || result <= 0) {
					throw new RuntimeException("Operating data of failure.");
				}
				return result;
			} else {
				return this.update(t);
			}
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<T> getList(T t, boolean isCache) {
		if (isCache) {
			try {
				return (List<T>) ObjectUtil.mapConvetObject(getCommonMapper().getList(t), t.getClass());
			} catch (Exception e) {
				logger.error(e);
				return new ArrayList<T>();
			}
		} else {
			return this.getList(t);
		}
	}

	@Override
	public T getById(String id, boolean isCache) {
		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer delete(T t, boolean isCache) {
		try {
			if (isCache) {
				Integer result = this.commonCacheMapper.delete(t);
				if (result == null || result <= 0) {
					throw new RuntimeException("Operating data of failure.");
				}
				return result;
			} else {
				return this.delete(t);
			}
		} catch (Exception e) {
			logger.error(e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * sqlwhere 传入 " where id='...' and ..." 这样的格式
	 */
	@Override
	public List<T> getList(final String sqlwhere) {
		try {
			Executer excuter=new Executer(){
				@Override
				public Object exec() {
					return getCommonMapper().getListBySqlWhere(sqlwhere);
				}
			};
			return (List<T>) ObjectUtil.mapConvetObject((List)execLocal(excuter),getEntryClass());
		} catch (Exception e) {
			logger.error(e);
			return new ArrayList<T>();
		}
	}
	
	public Class<T> getEntryClass(){
		if(entryClass!=null){
			return entryClass;
		}
		ParameterizedType parameterizedType = (ParameterizedType)this.getClass().getGenericSuperclass(); 
		if(parameterizedType.getActualTypeArguments().length==0){
			return null;
		}
		entryClass=  (Class<T>)(parameterizedType.getActualTypeArguments()[0]); 
		return entryClass;
	}
	Class<T> entryClass=null;

	@Override
	public T get(T t) {
		try {
			return (T) ObjectUtil.mapConvetObject(getCommonMapper().get(t), t.getClass());
		} catch (Exception e) {
			try {
				logger.error(e);
				return (T) ObjectUtil.createNewInstance(t.getClass());
			} catch (InstantiationException e1) {
				logger.error(e1);
				return null;
			} catch (IllegalAccessException e1) {
				logger.error(e1);
				return null;
			}
		}
	}
	private Object execLocal(Executer classLocal){
		Object o=null;
		try {
			ClassAttach attach=new ClassAttach();
			attach.put("class", this.getEntryClass());
			ClassContext.set(attach);
			o = classLocal.exec();
		}finally{
			ClassContext.remove();
		}
		return o;
	}
	
	
}
